package com.google.code.shardbatis.util;

import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;

import org.apache.ibatis.io.Resources;
import org.xml.sax.Attributes;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import org.xml.sax.helpers.DefaultHandler;

import com.google.code.shardbatis.builder.ShardConfigHolder;
import com.google.code.shardbatis.strategy.ShardSql;
import com.google.code.shardbatis.strategy.ShardStrategy;

public class ConfigHandler extends DefaultHandler {
	 private static final String SHARDBATIS_CONFIG_DTD =
	            "shardbatis-config.dtd";
	    private static final Map<String, String> DOC_TYPE_MAP = new HashMap<String, String>();
	    static {
	        DOC_TYPE_MAP.put("http://shardbatis.github.com/dtd/shardbatis-config.dtd".toLowerCase(),
	                SHARDBATIS_CONFIG_DTD);
	        DOC_TYPE_MAP.put("-//shardbatis.github.com//DTD Shardbatis 2.0//EN".toLowerCase(),
	                SHARDBATIS_CONFIG_DTD);
	    }
//	private static final Log log = LogFactory.getLog(ConfigHandler.class);
	private String parentElement;
	ShardConfigHolder configHolder;

	public ConfigHandler(ShardConfigHolder configHolder){
		this.configHolder = configHolder;
	}

	@Override
	public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
		if ("strategy".equals(qName)) {
			String table = attributes.getValue("tableName");
			String className = attributes.getValue("strategyClass");
			ShardStrategy strategy;
			try {
				Class clazz = Class.forName(className);
				strategy = (ShardStrategy) clazz.newInstance();
				configHolder.register(table, strategy);
			} catch (ClassNotFoundException e) {
				e.printStackTrace();
			} catch (InstantiationException e) {
				e.printStackTrace();
			} catch (IllegalAccessException e) {
				e.printStackTrace();
			}

		}
		if ("mapper".equals(qName)) {
			String id = attributes.getValue("id");
			String className = attributes.getValue("strategyClass");
			ShardSql strategy;
			try {
				Class clazz = Class.forName(className);
				strategy = (ShardSql) clazz.newInstance();
				configHolder.registerMapper(id, strategy);
			} catch (ClassNotFoundException e) {
				e.printStackTrace();
			} catch (InstantiationException e) {
				e.printStackTrace();
			} catch (IllegalAccessException e) {
				e.printStackTrace();
			}

		}
		if (("ignoreList".equals(qName)) || ("parseList".equals(qName))) {
			this.parentElement = qName;
		}

	}

	@Override
	public void characters(char[] ch, int start, int length) throws SAXException {
		if ("ignoreList".equals(this.parentElement)) {
			configHolder.addIgnoreId(new String(ch, start, length).trim());
		} else if ("parseList".equals(this.parentElement)) {
			configHolder.addParseId(new String(ch, start, length).trim());
		}
	}
	 public void error(SAXParseException e) throws SAXException {
         throw e;
     }


     public InputSource resolveEntity(String publicId, String systemId) throws IOException,
             SAXException {
         if (publicId != null)
             publicId = publicId.toLowerCase();
         if (systemId != null)
             systemId = systemId.toLowerCase();

         InputSource source = null;
         try {
             String path = DOC_TYPE_MAP.get(publicId);
             source = getInputSource(path, source);
             if (source == null) {
                 path = DOC_TYPE_MAP.get(systemId);
                 source = getInputSource(path, source);
             }
         }
         catch (Exception e) {
             throw new SAXException(e.toString());
         }
         return source;
     }
     private InputSource getInputSource(String path, InputSource source) {
         if (path != null) {
             InputStream in = null;
             try {
                 in = Resources.getResourceAsStream(path);
                 source = new InputSource(in);
             }
             catch (IOException e) {
             }
         }
         return source;
     }
}
